package luke.audio.processor;

import java.util.List;

/**
 * 鼓点叠加处理器
 * 在PCM音频数据上直接叠加快板声音，实现精准同步
 */
public class BeatOverlayProcessor {

    // 音频参数
    private static final int SAMPLE_RATE = 44100; // 采样率
    private static final int CHANNELS = 2; // 声道数（立体声）
    private static final int BYTES_PER_SAMPLE = 2; // 每个样本的字节数（16位）
    private static final int BYTES_PER_FRAME = CHANNELS * BYTES_PER_SAMPLE; // 每帧字节数（立体声16位=4字节）

    /**
     * 计算指定时间在PCM数据中的字节位置（确保帧对齐）
     *
     * @param timeMs 时间（毫秒）
     * @return 字节位置（帧对齐）
     */
    private static int calculateBytePosition(int timeMs) {
        // 计算样本数：(时间毫秒 * 采样率 / 1000)
        double samples = (timeMs * (double) SAMPLE_RATE / 1000.0);

        // 计算字节位置：样本数 * 每样本字节数 * 声道数
        long bytePosition = (long) (samples * BYTES_PER_FRAME);

        // 确保位置是帧对齐的（4字节边界）
        bytePosition = (bytePosition / BYTES_PER_FRAME) * BYTES_PER_FRAME;

        // 检查是否超出int范围
        if (bytePosition > Integer.MAX_VALUE) {
            System.err.println("[BEAT_DEBUG] 警告: 字节位置超出int范围: " + bytePosition);
            return Integer.MAX_VALUE;
        }

        return (int) bytePosition;
    }

    /**
     * 根据鼓点类型索引获取鼓点音效
     */

    public static byte[] getBeatSoundPcm(int beatSoundType) {
        switch (beatSoundType) {
            case 0:
                return BeatSoundGenerator.generateBeatSound();
            case 1:
                return BeatSoundGenerator.generateBubbleSound();
            case 2:
                return BeatSoundGenerator.generateDrumSound();
            case 3:
                return BeatSoundGenerator.generateTriangleSound();
            case 4:
                return BeatSoundGenerator.generateWoodenFishSound();
            case 5:
                return BeatSoundGenerator.generateSwordSound();
            default:
                return BeatSoundGenerator.generateBeatSound();
        }
    }

    /**
     * 将鼓点音效PCM数据叠加到原始音频PCM数据上
     *
     * @param originalPcm   原始音频PCM数据
     * @param beatSoundPcm  鼓点音效PCM数据
     * @param beatPositions 鼓点位置列表（毫秒）
     * @return 叠加鼓点后的PCM数据
     */
    public static byte[] overlayBeatSoundOnPcm(byte[] originalPcm, byte[] beatSoundPcm, List<Integer> beatPositions) {
        if (originalPcm == null || originalPcm.length == 0 || beatSoundPcm == null || beatSoundPcm.length == 0
                || beatPositions == null || beatPositions.isEmpty()) {
            return originalPcm;
        }

        // 创建输出数据副本
        byte[] outputData = originalPcm.clone();

        System.out.println("[BEAT_DEBUG] 开始叠加鼓点:");
        System.out.println("[BEAT_DEBUG] 原始PCM长度: " + originalPcm.length + " 字节");
        System.out.println("[BEAT_DEBUG] 鼓点音效长度: " + beatSoundPcm.length + " 字节");
        System.out.println("[BEAT_DEBUG] 鼓点数量: " + beatPositions.size());

        // 计算PCM数据对应的音频时长（毫秒）
        //公式: 音频时长（毫秒） = PCM数据长度（字节） / 每帧字节数（立体声16位=4字节） / 采样率（Hz） * 1000
        int pcmDurationMs = (int) ((originalPcm.length / (double) BYTES_PER_FRAME) / SAMPLE_RATE * 1000);
        System.out.println("[BEAT_DEBUG] PCM数据对应音频时长: " + pcmDurationMs + "ms");
        // 统计有效和无效的鼓点
        int validBeats = 0;
        int invalidBeats = 0;

        // 在每个鼓点位置叠加鼓点音效
        for (int i = 0; i < beatPositions.size(); i++) {
            int beatTimeMs = beatPositions.get(i);

            // 检查鼓点时间是否超出音频时长
            if (beatTimeMs >= pcmDurationMs) {
                invalidBeats++;
                if (i < 5 || i >= beatPositions.size() - 5) {
                    System.err.println("[BEAT_DEBUG] 鼓点时间超出音频时长: " + beatTimeMs + "ms >= " + pcmDurationMs + "ms");
                }
                continue;
            }

            // 计算鼓点在PCM数据中的位置（字节索引），确保对齐到立体声帧边界
            int beatPosition = calculateBytePosition(beatTimeMs);

            // 确保位置有效且不会越界，并且对齐到立体声帧边界
            if (beatPosition >= 0 && beatPosition < outputData.length && beatSoundPcm.length > 0) {
                // 确保位置是对齐的（4字节边界，因为立体声16位 = 4字节每帧）
                beatPosition = (beatPosition / BYTES_PER_FRAME) * BYTES_PER_FRAME;

                // 检查鼓点音效是否会超出PCM数据范围
                if (beatPosition + beatSoundPcm.length <= outputData.length) {
                    validBeats++;
                    if (i < 5 || i >= beatPositions.size() - 5) {
                        System.out.println("[BEAT_DEBUG] 叠加鼓点 " + i + " 位置: " + beatPosition + "ms");
                    }
                    // 叠加鼓点音效
                    PCMAudioProcessor.overlayPcmSound(outputData, beatSoundPcm, beatPosition);
                } else {
                    invalidBeats++;
                    if (i < 5 || i >= beatPositions.size() - 5) {
                        System.err.println("[BEAT_DEBUG] 鼓点位置越界: " + beatPosition + " + " + beatSoundPcm.length + " > " + outputData.length);
                    }
                }
            } else {
                invalidBeats++;
                if (i < 5 || i >= beatPositions.size() - 5) {
                    System.err.println("[BEAT_DEBUG] 无效的鼓点位置: " + beatPosition + " (数据长度: " + outputData.length + ")");
                }
            }
        }

        System.out.println("[BEAT_DEBUG] 鼓点叠加完成: 有效=" + validBeats + ", 无效=" + invalidBeats);

        return outputData;
    }
}